/*
 * @Description:
 * @Author: Evan Zhang. evan.holmes@foxmail.com
 * @Date: 2023-10-16 14:10:54
 * @LastEditTime: 2023-10-16 16:45:59
 * @LastEditors: Evan Zhang. evan.holmes@foxmail.com
 * @Reference:
 */
const axios = require("axios")

axios.get("https://www.baidu.com/").then(({ data }) => {
  const html = fastParseHTML(data)
  console.log(html)
})

/**
 * @description: 快速解析HTML，返回根节点
 * @return {*}
 * @param {*} data
 */
function fastParseHTML(data) {
  const tagFlow = tokenizer(data)
  sequence2struct(tagFlow)
  readContent(tagFlow, data)
  return {
    flow: tagFlow,
    root: findMainRoot(tagFlow)
  }
}

/**
 * @description: 标记器
 * @return {*}
 * @param {*} data
 */
function tokenizer(data) {
  const resultPool = []

  let idx = 0, len = data.length
  while (idx < len) {
    let str = data.substr(idx, len - idx + 1)

    const StartIdx = str.indexOf("<")
    const EndIdx = str.indexOf(">")
    if (EndIdx === -1) break

    const stringMiddle = str.substr(StartIdx, EndIdx - StartIdx + 1)
    const isCommentsCase = stringMiddle[1] === "!"
    const tagName = stringMiddle.split(" ")[0].replace("<", "").replace("/", "").replace(">", "")

    idx += EndIdx + 1

    if (!stringMiddle || !tagName) continue;

    resultPool.push({
      info: stringMiddle,
      tagName: tagName,
      position: [idx - 1 - EndIdx, idx],
      children: [],
      isStart: stringMiddle[1] !== "/",
      isCommentCase: isCommentsCase,
      isSingleTag: isCommentsCase ||// 是注释
        ["link", "meta"].includes(tagName) || // 是特殊单标签
        stringMiddle[stringMiddle.length - 2] === "/" // 是一般单标签
    });

  }
  return resultPool
}

/**
 * @description: 序列转结构
 * @return {*}
 * @param {*} tagFlow
 */
function sequence2struct(tagFlow) {
  const pool = [...tagFlow]
  let ret;
  const sequence = [];

  while (ret = pool.shift()) {
    const last = sequence[sequence.length - 1]

    if (ret.isStart && last) {
      last.children.push(ret)
      ret.parent = last
    }
    if (ret.isSingleTag) continue

    if (ret.isStart) {
      sequence.push(ret)
    } else if (last.tagName === ret.tagName) {
      last.endNode = ret
      sequence.pop()
      // 链接parent
      if (sequence.length)
        ret.parent = sequence[sequence.length - 1]
    }
  }
}

/**
 * @description: 获取根节点
 * @return {*}
 * @param {*} tagFlow
 */
function findMainRoot(tagFlow) {
  for (let i = 0, len = tagFlow.length; i < len; i++) {
    const ret = tagFlow[i];
    if (
      !Object.hasOwnProperty(ret, "parent") &&
      !ret.isSingleTag &&
      ret.isStart
    ) return ret;
  }
}

/**
 * @description: 读取节点内容
 * @return {*}
 * @param {*} tagFlow
 * @param {*} rawData
 */
function readContent(tagFlow, rawData) {
  tagFlow.forEach(element => {
    const pos = element.position
    if (element.isSingleTag) {
      element.info = rawData.substr(pos[0], pos[1] - pos[0])
    } else if (element.endNode) {
      const endPos = element.endNode.position
      element.info = rawData.substr(pos[0], endPos[1] - pos[0])
    }
  });
}